$TITLE ('RTX-51 CREATE SYSTEM CALL')
$SYMBOLS
$NOXREF
$NOCOND
$NOMOD51
$NORB
$PAGELENGTH(80) PAGEWIDTH(110)
;************************************************************************
;*									                                    *
;*    R T X - 5 1  :  CREATE SYSTEM CALL                                *
;*							     		                                *
;*----------------------------------------------------------------------*
;*                                                                      *
;*    Filename     :   RTXCREA.A51                                      *
;*    Language     :   Keil A-51                                        *
;*    Dev. system  :   Keil uVision2                                    *
;*    Targetsystem :   Any system based upon 8051 up                    *
;*                                                                      *
;*    Purpose      :   Implements the system call os_create_task        *
;*								     	                                *
;*----------------------------------------------------------------------*
;* Rev. |  Released   | Programmer    | Comments                        *
;*----------------------------------------------------------------------*
;*  0.1 |  16.1.90    | E. Glatz      | Changes for V3.18               *
;*  0.2 |   8.3.91    | Th. Fischler  | Changes for V4.0                *
;*      |  29.4.91    | Th. Fischler  | os_create_task implemented      *
;*      |   9.10.91   | Th. Fischler  | set task-number in              *
;*      |             |               | '?RTX_INTERNAL_NUM_TABLE'       *
;*      |  29.10.91   | Th. Fischler  | Do not start an already started *
;*      |             |               | task                            *
;*      |   8.4.92    | Th. Fischler  | Start of Fast-Tasks generalized *
;*      |             |               | for RTX-51 with Bank-Switching  *
;*      |  22.4.92    | Th. Fischler  | The actual Code-Bank will be    *
;*      |             |               | stored in the task kontext when *
;*      |             |               | the task is started             *
;*      |  4.06.1992  |               | RTXINS.INC converted to proc.   *
;*      | 23.03.1993  | Th. Fischler  | Set the register R7 to defined  *
;*      |             |               | state when task is started      *
;* 5.00 | 20.10.1994  | E. Glatz      | Release 5.00                    *
;* 5.12 | 27.10.1998  | M. Stolz      | Fixed mutual exclusion error in *
;*      |             |               | os_create_task (now excludes all*
;*      |             |               | task interrupts when inserting  *
;*      |             |               | into the ready list.            *
;* 7.00 | 13.11.2001  | T. Mueller    | Release 7.00                    *
;************************************************************************
;*    Copyright 1991 .. 2001 METTLER  &  FUCHS  AG,  CH-8953 Dietikon   *
;************************************************************************

$INCLUDE (RTXDEBUG.INC)
$INCLUDE (RTXIMASK.INC)


;*----------------------------------------------------------------------*
;*	I M P O R T S
;*----------------------------------------------------------------------*

$INCLUDE (RTXCONST.INC)
$INCLUDE (RTXEXTRN.INC)

;        FROM RTXDISP
EXTRN    CODE (?RTX_REDISPATCH)

;        FROM RTXINS
EXTRN    CODE  (?RTX_INSERT_RDY_PRIO)

;        FROM RTXCONF
EXTRN    DATA  (?B_CURRENTBANK)



;*----------------------------------------------------------------------*
;*	E X P O R T S
;*----------------------------------------------------------------------*

PUBLIC  _os_create_task


;*----------------------------------------------------------------------*
;*      C O N S T A N T S
;*----------------------------------------------------------------------*

;
;       Task Descriptor Definitions
;       ===========================
;
;       These constants are derived from the RTX-51/C-51 interface 
;       definition.
;
ITD_SIZE       EQU   7  ; Element-size of the task descriptor
TASKA_OFFS     EQU   0  ; Offset of the task startaddress in the task desc.
REGB_OFFS      EQU   2  ;  "            register bank       "
PRIO_OFFS      EQU   3  ;  "            priority            "
TASKNBR_OFFS   EQU   4  ;  "            task number         "
KNTXT_OFFS     EQU   5  ;  "            context address     "


;*----------------------------------------------------------------------*
;*      D U M M Y - S T A C K   D E C L A R A T I O N
;*----------------------------------------------------------------------*

?STACK         SEGMENT  IDATA
               RSEG     ?STACK
               DS 17


;*----------------------------------------------------------------------*
;*	P R O C E D U R E S
;*----------------------------------------------------------------------*

;*----------------------------------------------------------------------*
;*       O S _ C R E A T E _ T A S K
;*----------------------------------------------------------------------*
;*       Create a RTX task and include it in dispatching.
;*----------------------------------------------------------------------*
;*       Input:   - R7: Task-Number of task to start
;*                                       
;*       Output:  - completion status returned in R7:
;*
;*                   -1: NOT_OK
;*                    0: OK
;*----------------------------------------------------------------------*
;*       Internal Register usage :
;*          R0    : Task priority / Miscellaneous values
;*          R1    : Holds the internal task number
;*          R2/R3 : Task start address high & low
;*          R4    : Register bank of task / task_id
;*          R5/R6 : Context address of task high & low
;*          R7    : User task number
;*----------------------------------------------------------------------*

?RTX?_os_create_task?RTXCREA  SEGMENT CODE
                              RSEG    ?RTX?_os_create_task?RTXCREA

_os_create_task:
               DBG_SYS_ENTRY
               RTX_EXCLUDE_INT
               SETB  ?RTX_SUPERVISOR_MODE       ; Supervisor_mode := on
               RTX_ALLOW_DRV_INT

               ; Test if the task is not already started
               MOV   DPH, #HIGH(?RTX_USER_NUM_TABLE)
               MOV   A, #LOW(?RTX_USER_NUM_TABLE)
               ADD   A, R7
               MOV   DPL, A
               ; DPTR -> user_num_table[user_task_num]
               MOVX  A, @DPTR
               CLR   C
               SUBB  A, #NO_TASK
               JZ    TASK_OK                    ; Task does not exist
               JMP   ERR_EXIT


TASK_OK:
;     Search the corresponding initial task descriptor
               MOV   DPTR, #(?RTX_TASKCONST-ITD_SIZE)
               MOV   R0, #0                     ; R0 is descriptor counter
NEXT_ITD:      ; Load the task number of the taskdesc[R0]
               MOV   A, DPL
               ADD   A, #ITD_SIZE
               MOV   DPL, A
               MOV   A, DPH
               ADDC  A, #0
               MOV   DPH, A
               MOV   A, #TASKNBR_OFFS           ; Offset of task no in taskdesc.
               MOVC  A, @A+DPTR
               ; Compare the task numbers
               CLR   C
               SUBB  A, R7
               JZ    ITD_FOUND                  ; Task descriptor found
               ; Task descriptor not found, compare next
               INC   R0
               CJNE  R0, #?RTX_CNTTASK, NEXT_ITD
               ; The task descriptor was not found, return with error
               JMP   ERR_EXIT

ITD_FOUND:     ; Load the task descriptor values to registers for easier
               ; access
               MOV   A, #PRIO_OFFS
               MOVC  A, @A+DPTR
               MOV   R0, A                      ; R0 holds prio
               MOV   A, #TASKA_OFFS
               MOVC  A, @A+DPTR
               MOV   R2, A
               MOV   A, #TASKA_OFFS+1
               MOVC  A, @A+DPTR
               MOV   R3, A                      ; R2/R3 holds the task start adr
               MOV   A, #REGB_OFFS
               MOVC  A, @A+DPTR
               MOV   R4, A                      ; R4 holds reg-bank
               MOV   A, #KNTXT_OFFS
               MOVC  A, @A+DPTR
               MOV   R5, A
               MOV   A, #KNTXT_OFFS+1
               MOVC  A, @A+DPTR
               MOV   R6, A                      ; R5/R6 holds the task context adr

               ; Check if Fast Task (=driver task)
               MOV   A, R0
               CLR   C
               SUBB  A, #3                      ; Check if prio=3
               JZ    DRIVER
               JMP   NON_DRIVER

DRIVER:        ; It's a Fast Task (=driver task), check the used register bank
               MOV   A, R4
               CJNE  A, #1, DRIVER23

DRIVER1:       RTX_EXCLUDE_INT
               ; Check if reg bank used
               MOV   DPTR, #?RTX_TID_TABLE+16
               MOVX  A, @DPTR                   ; Get TID_TABLE[16]
               CJNE  A, #NIL_TID, ERR_EXIT_1
               ; Setup the TID table
               MOV   A, #0D0H                   ; Set-up task_id
               MOV   R4, A                      ; Temp storage of task_id
               MOVX  @DPTR, A
               MOV   R1, #16                    ; Set-up the task number
               RTX_ALLOW_DRV_INT
               ; Set R7 of task to defined state
               MOV   RB1R7, #0
               ; SP-Setup in context
               MOV   R0, #?RTX_FTASKDATA?1
               MOV   A, #?RTX_FTASKDATA?1
               ADD   A, #?RTX_INTREGSIZE+1
               MOV   @R0, A
               ; Reentrant stack setup in context
               INC   R0
               MOV   @R0, #HIGH(?RTX_FTASKCONTEXT?1)
               MOV   A, #LOW(?RTX_FTASKCONTEXT?1)
               ADD   A, #?RTX_EXTRENTSIZE-1
               INC   R0
               MOV   @R0, A
               ; Check if code bankswitching is enabled and store
               ; the actual code bank in the context
               JNB   ?RTX_BANKSW, NO_B1
               INC   R0
               MOV   @R0, ?B_CURRENTBANK
               ; Set up the initial PC in the stack
NO_B1:         MOV   A, #?RTX_FTASKDATA?1
               ADD   A, #?RTX_INTREGSIZE
               MOV   R0, A
               MOV   A, R3
               MOV   @R0, A                     ; Store lower start adr. in stack
               INC   R0
               MOV   A, R2
               MOV   @R0, A                     ; Store higher start adr. in stack
               JMP   CONT

ERR_EXIT_1:    JMP   ERR_EXIT                   ; Label only for relative jumps

DRIVER23:      CJNE  A, #2, DRIVER3

DRIVER2:       RTX_EXCLUDE_INT
               ; Check if reg bank used
               MOV   DPTR, #?RTX_TID_TABLE+17
               MOVX  A, @DPTR                   ; Get TID_TABLE[17]
               CJNE  A, #NIL_TID, ERR_EXIT_1
               ; Setup the TID-table
               MOV   A, #0D1H                   ; Set-up task_id
               MOV   R4, A                      ; Temp. storage of task_id
               MOVX  @DPTR, A
               MOV   R1, #17                    ; Set-up the task number
               RTX_ALLOW_DRV_INT
               ; Set R7 of task to defined state
               MOV   RB2R7, #0
               ; SP-Setup in context
               MOV   R0, #?RTX_FTASKDATA?2
               MOV   A, #?RTX_FTASKDATA?2
               ADD   A, #?RTX_INTREGSIZE+1
               MOV   @R0, A
               ; Reentrant tack setup in context
               INC   R0
               MOV   @R0, #HIGH(?RTX_FTASKCONTEXT?2)
               MOV   A, #LOW(?RTX_FTASKCONTEXT?2)
               ADD   A, #?RTX_EXTRENTSIZE-1
               INC   R0
               MOV   @R0, A
               ; Check if code bankswitching is enabled and store
               ; the actual code bank in the context
               JNB   ?RTX_BANKSW, NO_B2
               INC   R0
               MOV   @R0, ?B_CURRENTBANK
               ; Set up the initial PC in the stack
NO_B2:         MOV   A, #?RTX_FTASKDATA?2
               ADD   A, #?RTX_INTREGSIZE
               MOV   R0, A
               MOV   A, R3
               MOV   @R0, A                     ; Store lower start adr. in stack
               INC   R0
               MOV   A, R2
               MOV   @R0, A                     ; Store higher start adr. in stack
               JMP   CONT

DRIVER3:       RTX_EXCLUDE_INT
               ; Check if reg bank used
               MOV   DPTR, #?RTX_TID_TABLE+18
               MOVX  A, @DPTR                   ; Get TID_TABLE[18]
               CJNE  A, #NIL_TID, ERR_EXIT_1
               ; Setup the TID-table
               MOV   A, #0D2H                   ; Set-up task_id
               MOV   R4, A                      ; Temp storage of task_id
               MOVX  @DPTR, A
               MOV   R1, #18                    ; Set-up the task number
               RTX_ALLOW_DRV_INT
               ; Set R7 of task to defined state
               MOV   RB3R7, #0
               ; SP-Setup in context
               MOV   R0, #?RTX_FTASKDATA?3
               MOV   A, #?RTX_FTASKDATA?3
               ADD   A, #?RTX_INTREGSIZE+1
               MOV   @R0, A
               ; Reentrant stack setup in context
               INC   R0
               MOV   @R0, #HIGH(?RTX_FTASKCONTEXT?3)
               MOV   A, #LOW(?RTX_FTASKCONTEXT?3)
               ADD   A, #?RTX_EXTRENTSIZE-1
               INC   R0
               MOV   @R0, A
               ; Check if code bankswitching is enabled and store
               ; the actual code bank in the context
               JNB   ?RTX_BANKSW, NO_B3
               INC   R0
               MOV   @R0, ?B_CURRENTBANK
               ; Set up the initial PC in the stack
NO_B3:         MOV   A, #?RTX_FTASKDATA?3
               ADD   A, #?RTX_INTREGSIZE
               MOV   R0, A
               MOV   A, R3
               MOV   @R0, A                     ; Store lower start adr. in stack
               INC   R0
               MOV   A, R2
               MOV   @R0, A                     ; Store higher start adr. in stack
               JMP   CONT

;
NON_DRIVER:    RTX_EXCLUDE_INT
               ; Search free place in TID_TABLE
               MOV   R1, #0
               MOV   DPTR, #?RTX_TID_TABLE
NEXT_TID:      MOVX  A, @DPTR
               CJNE  A, #NIL_TID, NOT_FOUND
               JMP   EMPTY_FOUND
NOT_FOUND:     INC   DPTR
               INC   R1
               ; Check if all Standard Task (=Non-Driver) places checked
               CJNE  R1, #16, NEXT_TID
               ; already 16 tasks exists
               JMP   ERR_EXIT

EMPTY_FOUND:   ; Setup the TID-table
               MOV   B, R1                      ; Load the task number
               MOV   A, R0                      ; Load the prio
               RR    A
               RR    A                          ; Shift prio-bits to correct pos.
               ORL   A, B                       ; Build TID with task-nbr and prio
               MOV   R4, A                      ; Temp storage of task_id
               MOVX  @DPTR, A                   ; Store the TID in the table
               RTX_ALLOW_DRV_INT
               ; Store the context address in the table
               MOV   DPH, #HIGH(?RTX_KNTXT_PTR_TABLE)
               MOV   A, #LOW(?RTX_KNTXT_PTR_TABLE)
               ADD   A, R1
               ADD   A, R1                      ; kntxt_table has word offset
               MOV   DPL, A                     ; DPTR -> kntxt_table[task_nbr]
               MOV   A, R5
               MOVX  @DPTR, A                   ; Store the adr in the kntxt_table
               INC   DPTR
               MOV   A, R6
               MOVX  @DPTR, A
               ; R7 setup
               MOV   DPH, R5                    ; High Byte of context area
               INC   A
               MOV   DPL, A
               CLR   A
               MOVX  @DPTR, A                   ; R7 of the new task = 0
               ; PSW setup
               MOV   A, DPL
               ADD   A, #0BH                    ; Add PSW offset to DPTR
               MOV   DPL, A
               CLR   A
               MOVX  @DPTR, A                   ; PSW of the new task = 0
               ; Stack setup
               INC   DPTR
               MOV   A, #?STACK+1
               MOVX  @DPTR, A                   ; Set SP in kontext of new task
               ; Setup pointer to the stack in the context of the new task
               ; and store the task start address in the context stack
               MOV   A, R6
               ADD   A, #?RTX_EXTREGSIZE
               MOV   DPL, A                     ; DPTR is ptr. to stack context
               MOV   A, R3
               MOVX  @DPTR, A                   ; Store lower start addr. in stack
               INC   DPTR
               MOV   A, R2
               MOVX  @DPTR, A                   ; Store higher start addr. in stack
               ; Reentrant stack setup
               MOV   A, R6                      ; Low-Byte of kntxt-area
               ADD   A, #0FH                    ; rsp-Offset
               MOV   DPL, A
               MOV   A, R5
               MOVX  @DPTR, A                   ; store high-address of reentrant
                                                ; stack in rsp
               INC   DPTR
               MOV   A, R6
               ADD   A, #?RTX_EXTREGSIZE
               ADD   A, #?RTX_EXTSTKSIZE
               ADD   A, #?RTX_EXTRENTSIZE-1
               MOVX  @DPTR, A                   ; store low address
               ; Store the actual code bank number
               JNB   ?RTX_BANKSW, CONT
               INC   DPTR
               MOV   A, ?B_CURRENTBANK
               MOVX  @DPTR, A

               ; Table init for Fast Tasks (=Drivers) and Standard Tasks (=Non Drivers)
CONT:          MOV   A, R1                      ; Get the task-number
               RL    A
               RL    A                          ; ACC := 4 * task nbr.
               ADD   A, #LOW(?RTX_STATE_TABLE)
               MOV   DPL, A
               MOV   DPH, #HIGH(?RTX_STATE_TABLE)
               ; (DPTR)ptr.to state_table[task_nbr]
               ; now init the state-table
               CLR   A
               MOVX  @DPTR, A                   ; New task_state := ready
               INC   DPTR
               MOVX  @DPTR, A                   ; Set int mask_0 to 0
               INC   DPTR
               MOVX  @DPTR, A                   ; Set int mask_1 to 0
               INC   DPTR
               MOVX  @DPTR, A                   ; Set int mask_2 to 0
               ; store the internal task number in the external to internal
               ; task-num table
               MOV   DPH, #HIGH(?RTX_USER_NUM_TABLE)
               MOV   A, #LOW(?RTX_USER_NUM_TABLE)
               ADD   A, R7
               MOV   DPL, A
               ; DPTR -> user_num_table[user_task_num]
               MOV   A, R1
               MOVX  @DPTR, A                   ; Store the internal task-nbr
               ; store the external task number in the internal to external
               ; task-num table
               MOV   DPH, #HIGH(?RTX_INTERNAL_NUM_TABLE)
               MOV   A, #LOW(?RTX_INTERNAL_NUM_TABLE)
               ADD   A, R1
               MOV   DPL, A
               ; DPTR -> internal_num_table[internal task-number]
               MOV   A, R7
               MOVX  @DPTR, A                   ; Store the external task-nbr

               RTX_EXCLUDE_INT                  ; 27.10.98mes. Solves mutex bug
               MOV   A, R4
               CALL ?RTX_INSERT_RDY_PRIO

               MOV   R7, #OK                    ; All okay
               CLR   ?RTX_FULL_CONTEXT          ; Assign reduced context
               JMP   ?RTX_REDISPATCH

;
;	THIS IS A COMMON ERROR EXIT POINT
;
ERR_EXIT:
               RTX_EXCLUDE_INT
               MOV     R7, #NOT_OK
               JNB     ?RTX_REQ_REDISPATCH, NODISP ; Redispatch requested ?
               ; Redispatch
               CLR     ?RTX_FULL_CONTEXT
               JMP     ?RTX_REDISPATCH
NODISP  :      CLR     ?RTX_SUPERVISOR_MODE     ; Supervisor_mode := off
               DBG_SYS_EXIT
               RTX_ALLOW_INT
               RET
;
;   END OF MODULE
;
	END
